package com.ruoyi.quartz.task;

import cn.hutool.core.convert.Convert;
import com.ruoyi.common.enums.PlanStatusEnums;
import com.ruoyi.common.utils.DateCalculationUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.bean.Builder;
import com.ruoyi.ring.domain.*;
import com.ruoyi.ring.domain.dto.PhysicalConditionDTO;
import com.ruoyi.ring.domain.dto.PhysiologyInfoQueryDTO;
import com.ruoyi.ring.domain.dto.PhysiologyTaskQueryDTO;
import com.ruoyi.ring.domain.vo.ConditionScoreVO;
import com.ruoyi.ring.domain.vo.UserPhysiologyVO;
import com.ruoyi.ring.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;


@Slf4j
@Component("ocbvTask")
public class OcbvTask {


    @Resource
    private IRingPhysicalConditionService ringPhysicalConditionService;
    @Resource
    private IRingTodaySignService ringTodaySignService;
    @Resource
    private IRingHealthPlanService ringHealthPlanService;
    @Resource
    private IUserPhysiologySetService userPhysiologySetService;
    @Resource
    private IUserPhysiologyService userPhysiologyService;
    @Resource
    private IRingAppNoticeService appNoticeService;
    /**
     * 身体状况评分修改每日签分数
     */
    @Transactional(rollbackFor = Exception.class)
    public void signScoreTask(){
        try {
            log.info("身体状况评分修改每日签分数");
            Date date = new Date();
            Date yesterday = DateUtils.queryYesterday(date);
            List<RingTodaySign> todaySignList = ringTodaySignService.selectRingTodaySignList(Builder.of(RingTodaySign::new).with(RingTodaySign::setDailyValue, yesterday).build());
            todaySignList.forEach(todaySign ->{
                log.info(todaySign.getUserId().toString());
                ConditionScoreVO conditionScoreVO = ringPhysicalConditionService.queryConditionScore(Builder.of(PhysicalConditionDTO::new).
                        with(PhysicalConditionDTO::setDeviceSn, todaySign.getDeviceSn()).
                        with(PhysicalConditionDTO::setDailyValue, todaySign.getDailyValue()).
                        with(PhysicalConditionDTO::setUserId, todaySign.getUserId()).build());
                int totalScore = conditionScoreVO.getTotalScore();
                todaySign.setStatusScore(totalScore);
                ringTodaySignService.updateRingTodaySign(todaySign);
            });
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 健康计划周期计划
     */
    @Transactional(rollbackFor = Exception.class)
    public void cyclePlanTask(){
        try {
            log.info("健康计划周期计划");
            Date date = new Date();
            Date yesterday = DateUtils.queryYesterday(date);
            List<RingHealthPlan> healthPlanList = ringHealthPlanService.selectRingHealthPlanList(Builder.of(RingHealthPlan::new).
                    with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).build());
            healthPlanList.forEach(healthPlan ->{
                if(yesterday.equals(healthPlan.getEndDate())){
                    healthPlan.setPlanStatus(PlanStatusEnums.COMPLETED.getCode());
                    ringHealthPlanService.updateRingHealthPlan(healthPlan);
                    if("1".equals(healthPlan.getIdDefault())){
                        healthPlan.setId(null);
                        healthPlan.setPlanStatus(PlanStatusEnums.IN_PROGRESS.getCode());
                        healthPlan.setStartDate(date);
                        Date futureDate = DateCalculationUtil.queryFutureDate(date,healthPlan.getPlanCycle());
                        healthPlan.setEndDate(futureDate);
                        ringHealthPlanService.insertRingHealthPlan(healthPlan);
                    }
                }
            });
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 健康计划积分计划
     */
    @Transactional(rollbackFor = Exception.class)
    public void pointsPlanTask(){
        try {
            log.info("健康计划积分计划");
            List<RingHealthPlan> healthPlanList = ringHealthPlanService.selectRingHealthPlanList(Builder.of(RingHealthPlan::new).
                    with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).build());
            healthPlanList.forEach(healthPlan ->{
                int planPoints = healthPlan.getPlanPoints() == null ? 0 : healthPlan.getPlanPoints();
                healthPlan.setPlanPoints(planPoints +1);
                ringHealthPlanService.updateRingHealthPlan(healthPlan);
            });
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * 健康计划进度计划
     */
    @Transactional(rollbackFor = Exception.class)
    public void scheduleTask(){
        try {
            log.info("健康计划进度计划");
            List<RingHealthPlan> healthPlanList = ringHealthPlanService.selectRingHealthPlanList(Builder.of(RingHealthPlan::new).
                    with(RingHealthPlan::setPlanStatus, PlanStatusEnums.IN_PROGRESS.getCode()).build());
            healthPlanList.forEach(healthPlan ->{
                int planProgress = healthPlan.getPlanProgress() == null ? 0 : healthPlan.getPlanProgress();
                healthPlan.setPlanProgress(planProgress +1);
                ringHealthPlanService.updateRingHealthPlan(healthPlan);
            });
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 自动生成本月生理周期
     */
    @Transactional(rollbackFor = Exception.class)
    public void periodTask(){
        try {
            log.info("自动生成本月生理周期");
            Date date = new Date();
            Date yesterday = DateUtils.queryYesterday(date);
            List<UserPhysiologySet> physiologySets = userPhysiologySetService.selectUserPhysiologySetList(new UserPhysiologySet());
            physiologySets.forEach(p ->{
                Date startDate = p.getStartDate();
                if(DateUtils.isSameYearAndMonth(startDate,yesterday)){
                    return;
                }
                long userId = p.getUserId();
                long periodDays = p.getPeriodDays();
                long menstrualPeriodDays = p.getMenstrualPeriodDays();
                UserPhysiologyVO physiologyVO = userPhysiologyService.queryPhysiologyTaskInfo(Builder.of(PhysiologyTaskQueryDTO::new).
                        with(PhysiologyTaskQueryDTO::setPeriodDays,periodDays).
                        with(PhysiologyTaskQueryDTO::setMenstrualPeriodDays,menstrualPeriodDays).
                        with(PhysiologyTaskQueryDTO::setStartDate,startDate).
                        with(PhysiologyTaskQueryDTO::setSelectDate,yesterday).build());
                if(physiologyVO != null){
                    Date newStartDate = physiologyVO.getUpdStartDate();
                    UserPhysiology userPhysiology = userPhysiologyService.queryOnePhysiologyInfo(Builder.of(PhysiologyInfoQueryDTO::new).
                            with(PhysiologyInfoQueryDTO::setUserId, userId).
                            with(PhysiologyInfoQueryDTO::setSelectDate, newStartDate).build());
                    UserPhysiology physiology = Convert.convert(UserPhysiology.class,physiologyVO);
                    physiology.setUserId(userId);
                    physiology.setStartDate(newStartDate);
                    physiology.setPeriodDays(periodDays);
                    physiology.setMenstrualPeriodDays(menstrualPeriodDays);
                    if(userPhysiology != null){
                        physiology.setId(userPhysiology.getId());
                        userPhysiologyService.updateUserPhysiology(physiology);
                    }else {
                        userPhysiologyService.insertUserPhysiology(physiology);
                    }
                    p.setStartDate(newStartDate);
                    userPhysiologySetService.updateUserPhysiologySet(p);
                }
            });
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }
    /**
     * 生理周期提醒
     */
    @Transactional(rollbackFor = Exception.class)
    public void periodReminderTask(){
        try {
            Date date = new Date();
            Date recordDate = DateUtils.dateTime(DateUtils.YYYY_MM_DD, DateUtils.getDate());
            log.info("生理周期提醒");
            List<UserPhysiologySet> physiologySets = userPhysiologySetService.selectUserPhysiologySetList(new UserPhysiologySet());
            physiologySets.forEach(p ->{
                long userId = p.getUserId();
                Date startDate = p.getStartDate();
                long periodDays = p.getPeriodDays();
                long menstrualPeriodDays = p.getMenstrualPeriodDays();
                String reminderTime;
                if("".equals(p.getReminderTime()) || p.getReminderTime() == null){
                    reminderTime = " 00:00:00";
                }else {
                    reminderTime = " " + p.getReminderTime() + ":00";
                }

                UserPhysiologyVO physiologyVO = userPhysiologyService.queryPhysiologyTaskInfo(Builder.of(PhysiologyTaskQueryDTO::new).
                        with(PhysiologyTaskQueryDTO::setPeriodDays,periodDays).
                        with(PhysiologyTaskQueryDTO::setMenstrualPeriodDays,menstrualPeriodDays).
                        with(PhysiologyTaskQueryDTO::setStartDate,startDate).
                        with(PhysiologyTaskQueryDTO::setSelectDate,startDate).build());
                if(physiologyVO != null){
                    List<RingAppNotice> appNotices = appNoticeService.selectRingAppNoticeList(Builder.of(RingAppNotice::new).
                            with(RingAppNotice::setUserId,userId).
                            with(RingAppNotice::setRecordDate,recordDate).
                            with(RingAppNotice::setNoticeType,"1").build());
                    if(appNotices.size() == 0){
                        List<String> list = Arrays.stream(physiologyVO.getOvulationPeriod().split(",")).collect(Collectors.toList());
                        RingAppNotice appNotice = new RingAppNotice();
                        //生理期提醒
                        if("1".equals(p.getIsMenstrualPeriod())){
                            Object value = DateUtils.dateTime(DateUtils.queryYesterday(startDate)) + reminderTime;
                            Date reminderDate =  DateUtils.parseDate(value);
                            if(DateUtils.isSameYearMonthDay(reminderDate,date) && reminderDate.compareTo(date) < 0){
                                appNotice.setNoticeTitle("生理期提醒");
                                appNotice.setNoticeType("1");
                                appNotice.setNoticeContent("生理期预计1天开始");
                                appNotice.setUserId(userId);
                                appNotice.setRecordDate(recordDate);
                                appNoticeService.insertRingAppNotice(appNotice);
                            }

                        }
                        //排卵期提醒
                        if("1".equals(p.getIsOvulationPeriod())){
                            Object value = DateUtils.dateTime(DateUtils.queryYesterday(DateUtils.parseDate(list.get(0)))) + reminderTime;
                            Date reminderDate =  DateUtils.parseDate(value);
                            if(DateUtils.isSameYearMonthDay(reminderDate,date) && reminderDate.compareTo(date) < 0){
                                appNotice.setNoticeTitle("排卵期提醒");
                                appNotice.setNoticeType("1");
                                appNotice.setNoticeContent("排卵期预计1天开始");
                                appNotice.setUserId(userId);
                                appNotice.setRecordDate(recordDate);
                                appNoticeService.insertRingAppNotice(appNotice);
                            }
                        }
                        //排卵日提醒
                        if("1".equals(p.getIsPeriodDays())){
                            Object value = DateUtils.dateTime(DateUtils.queryYesterday(DateUtils.parseDate(physiologyVO.getOvulationDay()))) + reminderTime;
                            Date reminderDate =  DateUtils.parseDate(value);
                            if(DateUtils.isSameYearMonthDay(reminderDate,date) && reminderDate.compareTo(date) < 0){
                                appNotice.setNoticeTitle("排卵日提醒");
                                appNotice.setNoticeType("1");
                                appNotice.setNoticeContent("排卵日预计1天后");
                                appNotice.setUserId(userId);
                                appNotice.setRecordDate(recordDate);
                                appNoticeService.insertRingAppNotice(appNotice);
                            }
                        }
                        //排卵期结束提醒
                        if("1".equals(p.getIsOvulationPeriodEnd())){
                            Object value = DateUtils.dateTime(DateUtils.queryYesterday(DateUtils.parseDate(list.get(list.size()-1)))) + reminderTime;
                            Date reminderDate =  DateUtils.parseDate(value);
                            if(DateUtils.isSameYearMonthDay(reminderDate,date) && reminderDate.compareTo(date) < 0){
                                appNotice.setNoticeTitle("排卵期结束提醒");
                                appNotice.setNoticeType("1");
                                appNotice.setNoticeContent("排卵期预计最后一天");
                                appNotice.setUserId(userId);
                                appNotice.setRecordDate(recordDate);
                                appNoticeService.insertRingAppNotice(appNotice);
                            }
                        }
                    }

                }
            });
        }catch (Exception e){
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

}
